package com.da.landlord;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.da.finance.DaFinanceStatementService;
import com.googlecode.cswish.annotation.Rest;
import com.googlecode.cswish.model.PageInfo;
import com.googlecode.cswish.model.Reference;
import com.googlecode.cswish.oosearch.Condition;
import com.googlecode.cswish.oosearch.QLInfo;
import com.googlecode.cswish.struts.spring.GenericService;
import com.ra.landlord.FeeAdditionRecord;
import com.ra.landlord.FeeRecord;
import com.ra.landlord.FeeRule;
import com.ra.landlord.FeeRuleCfg;
import com.ra.landlord.FeeRuleCfgCalc;
import com.ra.landlord.FeeRuleCfgDesc;
import com.ra.landlord.LandlordUserService;
import com.ra.landlord.Meter;
import com.ra.landlord.Room;
import com.ra.landlord.constant.FeeRuleCalcMode;
import com.ra.landlord.constant.FeeRuleType;
import com.ra.order.rental.RentalOrder;
import com.ra.order.rental.RentalOrderService;
import com.ra.util.DateTimeUtil;

/**
 * 用于生成费用的service
 * @author Perter.Z
 *
 */
@Service
public class DaChargeItemService {
	
	private static final Log logger = LogFactory.getLog(DaChargeItemService.class);
	
	@Resource
	private GenericService genericService;

	@Resource
	private DaChargeBillService daChargeBillService;
	
	@Resource
	private LandlordUserService landlordUserService;
	
	@Resource
	private DaFeeRuleService daFeeRuleService;
	
	@Resource
	private DaFinanceStatementService daFinanceStatementService;
	
	@Resource
	private DaRoomService roomService;
	
	@Resource
	private RentalOrderService rentalOrderService;
	
	@PersistenceContext(unitName="espirit")
	protected EntityManager em;
	
	public List<DaChargeItem> getChargeItemBy(DaRoom room){
		
		return null;
	}
	
	
	/**
	 * 首次出租房源时，产生的针对了room的租金，及押金
	 * @param room
	 * @return
	 */
	@Rest(type = "add")
	public void createFirstChargeItems( DaRoom room,DaAgreement agreement){
		
		//费用项
		List<DaChargeItem>  chargeItems = new ArrayList<DaChargeItem>();
		DaChargeItem  chargeItem = new DaChargeItem();
		//付几
		Integer payNum = agreement.getPayNum();
		//押金
		BigDecimal deposit = agreement.getDeposit();
		
		//租金
		BigDecimal rentPay  = agreement.getRentPay();
		
		//获取优惠类型 0表示一次性优惠 1是每月僡
		//Integer  breakType = agreement.getBreakType();
		
		//租金对象
		if( rentPay != null){
			chargeItem.setName("房租");
			Date beginDate = agreement.getRentBeginDate();
			//时间段
			chargeItem.setDateBeginRecv(beginDate);
			chargeItem.setDateEndRecv(getEndDate(-1, getEndDate(payNum,beginDate,2),5) );
			
			chargeItem.setRoom(room);
			chargeItem.setFeeRuleCfg(null);
			BigDecimal resultPrice = rentPay.multiply(new BigDecimal(payNum));
			
			//应收费用  刚出租时默认 已收取付几的费用
			chargeItem.setPriceActual(resultPrice);
			chargeItem.setPriceRecv(resultPrice);
			
			//设置收取状态 1表示已收取
			chargeItem.setStatus(DaChargeItem.STATUS_PAID);
			
			// 0表示房租
			chargeItem.setChargeType(0);
			chargeItems.add(chargeItem);
			
			daFinanceStatementService.addInternal(room, resultPrice, 1, new Date(), 0, "房租");
			
		}
		
		// 押金 对象 yj
		if ( deposit != null){
			chargeItem = new DaChargeItem();
			chargeItem.setName("押金");
			chargeItem.setStatus(DaChargeItem.STATUS_PAID);
			chargeItem.setRoom(room);
			
			//实收多少
			chargeItem.setPriceActual(deposit);
			//应用 没有应收的概念。
			chargeItem.setPriceRecv(deposit);
			
			//时间段
			chargeItem.setDateBeginRecv(agreement.getRentBeginDate());
			Date endDate = agreement.getRentEndDate();
			if( null == endDate){
				endDate = getEndDate(agreement.getRentPeriod(),agreement.getRentBeginDate(),1);
			}
			chargeItem.setDateEndRecv(getEndDate(-1,endDate,5));
			
			//设置为固定费用
			chargeItem.setChargeType(1);
			chargeItems.add(chargeItem);
			
			SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd");
			
			StringBuilder sb = new StringBuilder();
			sb.append(sf.format(chargeItem.getDateBeginRecv()));
			sb.append("至"+sf.format(chargeItem.getDateEndRecv()));
			daFinanceStatementService.addInternal(room, deposit, 2, new Date(), 0, sb.toString());
		}
		
		//得到房间的固定费用  独立费用
		List<DaFeeRule> roomFeeRule = room.getFeeRules();
		for (DaFeeRule daFeeRule : roomFeeRule) {
			FeeRuleCfg cfg = daFeeRule.getFeeRuleCfg();
			
			//固定费用
			if(cfg!=null && cfg.getFeeRuleCfgDesc()!=null && cfg.getFeeRuleCfgDesc().getType()==FeeRuleType.fixed && cfg.getFeeRuleCfgCalc()!=null){
				BigDecimal price = cfg.getFeeRuleCfgCalc().getPrice();
				chargeItem = new DaChargeItem();
				chargeItem.setName(cfg.getFeeRuleCfgDesc().getName());
				chargeItem.setStatus(DaChargeItem.STATUS_PAID);
				chargeItem.setChargeType(3);
				chargeItem.setRoom(room);
				chargeItem.setPriceRecv(price.multiply(new BigDecimal(payNum)));
				chargeItem.setPriceActual(price.multiply(new BigDecimal(payNum)));
				chargeItem.setDateBeginRecv(agreement.getRentBeginDate());
				chargeItem.setDateEndRecv(getEndDate(-1, getEndDate(payNum,agreement.getRentBeginDate(),2),5) );
				chargeItems.add(chargeItem);
				daFinanceStatementService.addInternal(room, price, 1, new Date(), 0, cfg.getFeeRuleCfgDesc().getName());
			}
			
		}
		//TODO 房源的固定费用 公摊
		
		room.setAgreement(agreement);
		daChargeBillService.createChargeBill(chargeItems, room, new BigDecimal(0));
		
	}
	
	
	/**
	 * 创建一条 房租收费项
	 * @param room
	 * @param lastItem
	 */
	@Rest(type = "add")
	public void createRentChargeItem(DaRoom room,DaChargeItem lastItem){
		//得到房间所对应的有效合约
		DaAgreement agreement = room.getAgreement();
		DaChargeItem newItem = new DaChargeItem();
		newItem.setRoom( room );
		newItem.setChargeType( 0 );
		newItem.setName( "房租" );
		//未收取
		newItem.setStatus( 0 );
		
		//把开始时间设置成为上一次的结束时间
		newItem.setDateBeginRecv(getEndDate(1, lastItem.getDateEndRecv(),5));
		//计算出费项的结束时间
		newItem.setDateEndRecv(getEndDate(-1,getEndDate(agreement.getPayNum(), newItem.getDateBeginRecv(), 2),5));
		
		BigDecimal rentPay = agreement.getRentPay();

		newItem.setPriceRecv( rentPay.multiply( new BigDecimal( agreement.getPayNum()) ) );
		
		//创建固定费用 房源公摊
		createFixedChargeItem(room,lastItem.getDateBeginRecv(),lastItem.getDateEndRecv());
		
		//创建独立费用
		genericService.add(newItem);
	}
	
	
	/**
	 * 生成某个时间段的固定费用 公摊
	 * @param room
	 * @param startDate
	 * @param endDate
	 */
	public void createFixedChargeItem(DaRoom room,Date startDate,Date endDate){
		room = genericService.load(room);
		
		List<FeeRuleCfg> fixeds = daFeeRuleService.searchFixedFeeRule(room.getSuite());
		if( fixeds == null ||room.getRentState() !=0 )return;
		
		//1合租 0整租
		if(room.getSuite().getRentType()==1){
			List<DaRoom> rentRooms = room.getSuite().getRentRooms();
			if(rentRooms == null || rentRooms.size()<=0 )return;
			
			for (FeeRuleCfg feeRuleCfg : fixeds) {
				DaChargeItem newItem = new DaChargeItem();
				newItem.setRoom( room );
				//3表示固定费用
				newItem.setChargeType( 3 );
				//未收取
				newItem.setStatus( 0 );
				String itemName = feeRuleCfg.getFeeRuleCfgDesc().getName();
				newItem.setName(itemName);
				newItem.setDateBeginRecv(startDate);
				newItem.setDateEndRecv(endDate);
				//TODO 公摊 
				newItem.setPriceRecv(feeRuleCfg.getFeeRuleCfgCalc().getPrice().divide(new BigDecimal(rentRooms.size()),2,BigDecimal.ROUND_UP));
				
				genericService.add(newItem);
				
			}
			
		}else{
			for (FeeRuleCfg feeRuleCfg : fixeds) {
				DaChargeItem newItem = new DaChargeItem();
				newItem.setRoom( room );
				//3表示固定费用
				newItem.setChargeType( 3 );
				//未收取
				newItem.setStatus( 0 );
				String itemName = feeRuleCfg.getFeeRuleCfgDesc().getName();
				newItem.setName(itemName);
				newItem.setDateBeginRecv(startDate);
				newItem.setDateEndRecv(endDate);
				
				newItem.setPriceRecv(feeRuleCfg.getFeeRuleCfgCalc().getPrice());
				
				genericService.add(newItem);
			}
		}
		
	}
	
	
	/**
	 * 产生一笔抄表费用 feeRule已经持久的化到数据库中
	 * @param feeRule
	 * @throws ParseException 
	 */
	@Rest(type = "add")
	public void createMeterChargeItems(DaFeeRule feeRule ) throws ParseException{
		
		feeRule = canCreateCharge(feeRule);
		
		if(feeRule == null)
			return;
		
		DaSuite suite = feeRule.getSuite();
		
		//得到所有已出租的房间
		List<DaRoom> rentRooms = suite.getRentRooms();
		
		//得到收费规则的各项依据项
		FeeRuleCfg cfg = feeRule.getFeeRuleCfg();
		FeeRuleCfgDesc desc = cfg.getFeeRuleCfgDesc();
		FeeRuleCfgCalc calc = cfg.getFeeRuleCfgCalc();
		
		//拿到当前的抄表
		DaMeter currMeter  = feeRule.getMeters().get(0);
		
		//上一次的刻度
		DaMeter preMeter = feeRule.getMeters().get(1);
		
		
		//刻度计算
		BigDecimal currCount = currMeter.getCount();
		BigDecimal preCount = preMeter.getCount();
		BigDecimal resultCount = currCount.subtract(preCount);
		
		//计算出刻度所对应的金额  总金额 
		BigDecimal resultPrice = calc.getPrice().multiply(resultCount);
		
		//计算出两次抄表相隔的天数
		Integer dayCount = daysBetween(preMeter.getCheckTime(),currMeter.getCheckTime());
		if( dayCount.equals(0)){
			dayCount = 1;
		}
		
		//整租情况的费用计算 (按照刻度直接计算即可,不需要按照天数计算)
		if( suite.getRentType() == 0 ){
			createMeterChargeItem(feeRule, rentRooms.get(0), desc.getName(), preMeter, currMeter, resultPrice);
		}else if( suite.getRentType() == 1 ){
			
			List<DaRoom> rooms = suite.getRentRooms();
			
			Map<DaRoom,Integer> eachDayCount = new HashMap<DaRoom,Integer> ();
			Integer totalCount = 0;
			
			for (DaRoom daRoom : rooms) {
				//得到房间的有效合约
				DaAgreement agreement = daRoom.getAgreement();
				//得到入住日期
				Date inDate = agreement.getRentBeginDate();
				
				Integer count = dayCount;
				if(betweenDate(inDate,preMeter.getCheckTime(),currMeter.getCheckTime())){
					count = daysBetween(inDate,currMeter.getCheckTime());
				}
				
				//得到每个房间入住的天数
				eachDayCount.put(daRoom, count);
				
				totalCount+=count;
			}
			for (DaRoom daRoom : rooms) {
				Integer roomCount = eachDayCount.get(daRoom);
				////得到房间应收的费用 总费用*房间天数/总天数
				BigDecimal roomPrice  = resultPrice.multiply(new BigDecimal(roomCount)).divide(new BigDecimal(totalCount),2,BigDecimal.ROUND_UP);
				createMeterChargeItem(feeRule, daRoom, desc.getName(), preMeter, currMeter, roomPrice);
			}
			
		}
		
	}
	
	public void createMeterChargeItem(DaFeeRule suiteFeeRule, List<DaFeeRule> roomFeeRules) {
		Date now = new Date();
		if (roomFeeRules ==  null || roomFeeRules.size() ==0 ){
			if(suiteFeeRule == null || suiteFeeRule.getSuite().getRentRooms().size() == 0) {
				return;
			}
			
			List<DaMeter> meters = suiteFeeRule.getMeters();
			DaMeter currMeter  = meters.get(0);
			DaMeter preMeter = meters.get(1);

			BigDecimal currCount = currMeter.getCount();
			BigDecimal preCount = preMeter.getCount();
			BigDecimal resultCount = currCount.subtract(preCount);
			
			BigDecimal resultPrice = suiteFeeRule.getFeeRuleCfg().getFeeRuleCfgCalc().getPrice().multiply(resultCount);
			
			//计算出两次抄表相隔的天数
			Integer dayCount = daysBetween(preMeter.getCheckTime(),currMeter.getCheckTime());
			if( dayCount.equals(0)){
				dayCount = 1;
			}
			Map<DaRoom,Integer> eachDayCount = new HashMap<DaRoom,Integer> ();
			Integer totalCount = 0;
			
			for (DaRoom daRoom : suiteFeeRule.getSuite().getRentRooms()) {
				DaAgreement agreement = daRoom.getAgreement();
				Date inDate = agreement.getRentBeginDate();
				Integer count = dayCount;
				if(betweenDate(inDate,preMeter.getCheckTime(),currMeter.getCheckTime())){
					count = daysBetween(inDate,currMeter.getCheckTime());
				}
				//得到每个房间入住的天数
				eachDayCount.put(daRoom, count);
				totalCount+=count;
			}
			for (DaRoom daRoom : suiteFeeRule.getSuite().getRentRooms()) {
				Integer roomCount = eachDayCount.get(daRoom);
				////得到房间应收的费用 总费用*房间天数/总天数
				BigDecimal roomPrice  = resultPrice.multiply(new BigDecimal(roomCount)).divide(new BigDecimal(totalCount),2,BigDecimal.ROUND_UP);
				createMeterChargeItem(suiteFeeRule, daRoom, suiteFeeRule.getFeeRuleCfg().getFeeRuleCfgDesc().getName(), preMeter, currMeter, roomPrice, now);
			}
		}else{
			//主表和子表费用计算
			if(suiteFeeRule != null) {
				BigDecimal resultCount = BigDecimal.valueOf(0);
				Map<DaRoom,Integer> eachDayCount = new HashMap<DaRoom,Integer> ();
				Map<DaRoom,BigDecimal> eachMeterCount = new HashMap<DaRoom,BigDecimal> ();
				Integer totalCount = 0;
				//TODO prevMeter获取错误需要修改
				for (DaFeeRule feeRule : roomFeeRules) {
					List<DaMeter> meters = feeRule.getMeters();
					DaMeter currMeter  = meters.get(0);
					DaMeter preMeter = meters.get(1);
					if(feeRule.getChargeItems() == null || feeRule.getChargeItems().size() == 0) {
						int i = 2;
						while (i<meters.size() && meters.get(i).getCheckTime().compareTo(feeRule.getRoom().getAgreement().getRentBeginDate())>=0) {
							preMeter = meters.get(i++);
						}
					}else{
						DaChargeItem chargeItem = feeRule.getChargeItems().get(0);
						int i = 2;
						while (i<meters.size() && meters.get(i).getCheckTime().compareTo(chargeItem.getCreateChargeTime())>=0) {
							preMeter = meters.get(i++);
						}
					}
					BigDecimal currCount = currMeter.getCount();
					BigDecimal preCount = preMeter.getCount();
					eachMeterCount.put(feeRule.getRoom(),currCount.subtract(preCount));
					resultCount = resultCount.add(currCount.subtract(preCount));
					
					Integer dayCount = daysBetween(preMeter.getCheckTime(),currMeter.getCheckTime());
					if( dayCount.equals(0)){
						dayCount = 1;
					}
					DaAgreement agreement =  feeRule.getRoom().getAgreement();
					Date inDate =  agreement.getRentBeginDate();
					Integer count = dayCount;
					if(betweenDate(inDate,preMeter.getCheckTime(),currMeter.getCheckTime())){
						count = daysBetween(inDate,currMeter.getCheckTime());
					}
					//得到每个房间入住的天数
					eachDayCount.put(feeRule.getRoom(), count);
					totalCount+=count;
				}
				
				DaMeter suitePrevMeter = suiteFeeRule.getMeter(1);
				DaFeeRule firstFeeRule = roomFeeRules.get(0);
				if(firstFeeRule.getChargeItems() == null || firstFeeRule.getChargeItems().size() == 0) {
					//如果没有抄过表，则主表取具有该表的房间中最早的合约之后最近的一次抄表
					Date earliestRentBeginDate = firstFeeRule.getRoom().getAgreement().getRentBeginDate();
					for (DaFeeRule roomFeeRule : roomFeeRules) {
						if (roomFeeRule.getRoom().getAgreement().getRentBeginDate().before(earliestRentBeginDate)) {
							earliestRentBeginDate = roomFeeRule.getRoom().getAgreement().getRentBeginDate(); 
						}
					}
					int i = 2;
					while (i<suiteFeeRule.getMeters().size() && suiteFeeRule.getMeters().get(i).getCheckTime().compareTo(earliestRentBeginDate)>=0) {
						suitePrevMeter= suiteFeeRule.getMeters().get(i++);
					}
				}else{
					DaChargeItem chargeItem = firstFeeRule.getChargeItems().get(0);
					int i = 2;
					while (i<suiteFeeRule.getMeters().size() && suiteFeeRule.getMeters().get(i).getCheckTime().compareTo(chargeItem.getCreateChargeTime())>=0) {
						suitePrevMeter = suiteFeeRule.getMeters().get(i++);
					}
				}
				createMeterChargeItem(suiteFeeRule, suiteFeeRule.getSuite(), suiteFeeRule.getFeeRuleCfg().getFeeRuleCfgDesc().getName(), suitePrevMeter, suiteFeeRule.getMeter(0), suiteFeeRule.getMeter(0).getCount().subtract(suitePrevMeter.getCount()).multiply(suiteFeeRule.getFeeRuleCfg().getFeeRuleCfgCalc().getPrice()), now);//only for deleting meter on suite to delete others chargeItem
				BigDecimal needShareCount = suiteFeeRule.getMeter(0).getCount().subtract(suitePrevMeter.getCount()).subtract(resultCount);
				BigDecimal needSharePrice = needShareCount.multiply(suiteFeeRule.getFeeRuleCfg().getFeeRuleCfgCalc().getPrice());
				for (DaFeeRule feeRule : roomFeeRules) {
					Integer roomCount = eachDayCount.get(feeRule.getRoom());
					////得到房间应收的费用 总费用*房间天数/总天数
					BigDecimal roomPrice  = needSharePrice.multiply(new BigDecimal(roomCount)).divide(new BigDecimal(totalCount),2,BigDecimal.ROUND_UP).add(eachMeterCount.get(feeRule.getRoom()).multiply(feeRule.getFeeRuleCfg().getFeeRuleCfgCalc().getPrice()));
					createMeterChargeItem(feeRule, feeRule.getRoom(), feeRule.getFeeRuleCfg().getFeeRuleCfgDesc().getName(), feeRule.getMeter(1), feeRule.getMeter(0), roomPrice, now);
				}
				
			} else {//只有子表没有主表
				for (DaFeeRule feeRule : roomFeeRules) {
					List<DaMeter> meters = feeRule.getMeters();
					DaMeter currMeter  = meters.get(0);
					DaMeter preMeter = meters.get(1);
					BigDecimal currCount = currMeter.getCount();
					BigDecimal preCount = preMeter.getCount();
					BigDecimal roomPrice  = currCount.subtract(preCount).multiply(feeRule.getFeeRuleCfg().getFeeRuleCfgCalc().getPrice());
					createMeterChargeItem(feeRule, feeRule.getRoom(), feeRule.getFeeRuleCfg().getFeeRuleCfgDesc().getName(), preMeter, currMeter, roomPrice, currMeter.getCheckTime());
				}
			}
		}
	}
	
	/**
	 * 用于判断是否符合创建条件 如果符合，将返回持久化的 DaFeeRule对象，否则返回空
	 * @return
	 */
	//TODO 准备废弃
	private DaFeeRule canCreateCharge(DaFeeRule feeRule){
		
		if ( feeRule == null || feeRule.getId() == null) 
			return null;
		
		feeRule = genericService.load( feeRule );
		
		//不存在抄表数据 或不存在关联的房源
		if( feeRule.getMeters() == null || feeRule.getMeters().size()<2 || feeRule.getSuite() == null ){
			return null;
		}
		
		//得到收费规则的各项依据项
		FeeRuleCfg cfg = feeRule.getFeeRuleCfg();
		FeeRuleCfgDesc desc = cfg.getFeeRuleCfgDesc();
		FeeRuleCfgCalc calc = cfg.getFeeRuleCfgCalc();
		
		if( cfg ==null || desc == null || calc == null)
			return null;
		
		//表示不是抄表费用
		if( desc.getType() != FeeRuleType.meter){
			return null;
		}
		
		DaSuite suite = feeRule.getSuite();
		
		//得到所有已出租的房间
		List<DaRoom> rentRooms = suite.getRentRooms();
		
		//不存在出租的房间 
		if( rentRooms ==null || rentRooms.size() == 0 ){
			return null;
		}
		
		return feeRule;
	}
	
	
	/**
	 * 创建一条抄表收费项
	 * @param feeRule
	 * @param room
	 * @param itemName
	 * @param preMeter
	 * @param currMeter
	 * @param resultPrice
	 */
	private void createMeterChargeItem(DaFeeRule feeRule,DaRoom room,String itemName,DaMeter preMeter,DaMeter currMeter,BigDecimal resultPrice){
		
		DaChargeItem newItem = new DaChargeItem();
		newItem.setFeeRuleCfg(feeRule.getFeeRuleCfg());
		//整租的取，第一个房间
		newItem.setRoom(room);
		newItem.setName(itemName);
		
		newItem.setMeter1(preMeter);
		newItem.setMeter2(currMeter);
		newItem.setChargeType(2);
		
		//时间取抄表时间
		newItem.setDateBeginRecv(preMeter.getCheckTime());
		newItem.setDateEndRecv(currMeter.getCheckTime());
		
		//设置应收金额
		newItem.setPriceRecv(resultPrice.setScale(2,BigDecimal.ROUND_UP));
		
		//费用刚生成，设置为未收取状态
		newItem.setStatus(DaChargeItem.STATUS_CONFIRMED);
		
		genericService.add(newItem);
		
	}
	/**
	 * 创建一条抄表收费项
	 * @param feeRule
	 * @param room
	 * @param itemName
	 * @param preMeter
	 * @param currMeter
	 * @param resultPrice
	 */
	private void createMeterChargeItem(DaFeeRule feeRule,DaRoom room,String itemName,DaMeter preMeter,DaMeter currMeter,BigDecimal resultPrice, Date createChargeTime){
		DaChargeBillRecord dbChargeBillRecord = getOrGenerateChargeBillRecord(room);
		RentalOrder latestRentalOrder = roomService.getRentalOrder(dbChargeBillRecord);
		DaChargeItem newItem = new DaChargeItem();
		newItem.setFeeRuleCfg(feeRule.getFeeRuleCfg());
		//整租的取，第一个房间
		newItem.setRoom(room);
		newItem.setName(itemName);
		
		newItem.setMeter1(preMeter);
		newItem.setMeter2(currMeter);
		newItem.setChargeType(2);
		
		//时间取抄表时间
		newItem.setDateBeginRecv(preMeter.getCheckTime());
		newItem.setDateEndRecv(currMeter.getCheckTime());
		
		//设置应收金额
		newItem.setPriceRecv(resultPrice.setScale(2,BigDecimal.ROUND_UP));
		
		if (latestRentalOrder == null) {
			newItem.setStatus(DaChargeItem.STATUS_CONFIRMED);
		} else {
			newItem.setStatus(DaChargeItem.STATUS_NEED_CONFIRM);
		}
		
		newItem.setCreateChargeTime(createChargeTime);
		//newItem.setChargeBillRecord(dbChargeBillRecord);
		//genericService.add(newItem);
		dbChargeBillRecord.setAmountRecv(dbChargeBillRecord.getAmountRecv().add(newItem.getPriceRecv()).setScale(2, RoundingMode.HALF_UP));
		dbChargeBillRecord.getChargeItems().add(newItem);
		genericService.merge(dbChargeBillRecord);
	}
	
	private void createMeterChargeItem(DaFeeRule feeRule,DaSuite suite,String itemName,DaMeter preMeter,DaMeter currMeter,BigDecimal resultPrice, Date createChargeTime){
		
		DaChargeItem newItem = new DaChargeItem();
		newItem.setFeeRuleCfg(feeRule.getFeeRuleCfg());
		//整租的取，第一个房间
		newItem.setSuite(suite);;
		newItem.setName(itemName);
		
		newItem.setMeter1(preMeter);
		newItem.setMeter2(currMeter);
		newItem.setChargeType(2);
		
		//时间取抄表时间
		newItem.setDateBeginRecv(preMeter.getCheckTime());
		newItem.setDateEndRecv(currMeter.getCheckTime());
		
		//设置应收金额
		newItem.setPriceRecv(resultPrice.setScale(2,BigDecimal.ROUND_UP));
		
		//费用刚生成，设置为未收取状态
		newItem.setStatus(DaChargeItem.STATUS_CONFIRMED);
		newItem.setCreateChargeTime(createChargeTime);
		
		genericService.add(newItem);
		
	}
	
	
	/**
	 * 进入收租页面
	 * @param model
	 * @param start
	 * @param limit
	 * @param sort
	 * @param dir
	 * @param oldSearch
	 * @param qlInfoRef
	 * @return
	 */
	@Rest(type = "search")
	public PageInfo<DaRoom> chargeIndex(DaRoom model,int start,int limit,String sort, String dir, boolean oldSearch, Reference<QLInfo> qlInfoRef){
		
		//当前用户下已出租的
		model.setRentState(0);
		
		//先验证是否有新的收费项产生。
		autoCreateChargeItem();
		
		//房东为核心条件
		PageInfo<DaRoom> pageInfo = genericService.search(model, start, limit, sort, dir, oldSearch, qlInfoRef);
		
		return pageInfo;
	}
	
	
	
	/**
	 * 自动产生房租费用 进行智能判断，然后自动产生房租费用
	 */
	public void autoCreateChargeItem(){
		SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");  
		
		DaRoom room = new DaRoom();
		room.setRentState(0);
		
		List<DaRoom> rooms = genericService.searchByModel(room, Condition.DEFAULT, false, false).getData();
		
		Date currDate = new Date();
		for (DaRoom daRoom : rooms) {
			triggerCreateCharge(sdf, currDate, daRoom);
			
		}
	}

	
	public void triggerCreateCharge(SimpleDateFormat sdf, Date currDate,
			DaRoom daRoom) {
		
		//当退租或空间删除时，这个合约一定要把它清除掉，否则这里可能会取到多条有效数据。
		DaAgreement agreement = daRoom.getAgreement();
		if(agreement == null ) return;
		Integer advanceNum = agreement.getAdvanceNum();
		
		//HQL 找到最后一条房租收费项  不用担心中间没有产生费用，如果不是手动改数据库，，这个问题不可能产生 
		DaChargeItem item = new DaChargeItem();
		item.setRoom(daRoom);
		item.setChargeType(0);
		Condition condition = new Condition();
		condition.setSort("id");
		condition.setDir("desc");
		condition.setSize(1);
		
		item = genericService.searchByModel(item, condition).getData(0);
		
		if( item == null){
			logger.error("严重错误：理论上已出租房源的房租类型的charItem，不可能为空，得却出现了空值!");
			return;
		}
		
		
		//数据库中记录的日期
		Date endDate = item.getDateEndRecv();
		try {
			endDate=sdf.parse(sdf.format(endDate));
			//markOne
			endDate = getEndDate(advanceNum>0?-advanceNum:advanceNum,endDate,5);
		} catch (ParseException e) {
			logger.error("日期格式化出错");
			return;
		}
		
		//当前日期在数据库记录的日期之后，则要生成费用。(提天多少天，则把数据库日库前置再计算 look:markOne)
		if( endDate.before(currDate)){
			createRentChargeItem(daRoom,item);
			triggerCreateCharge(sdf,currDate,daRoom);
		}
		
		genericService.merge(daRoom);
	}
	
	
	
	/**
	 * 展示房间下，所有的收费项  带收租功能!
	 * @param room
	 * @return
	 */
	@Rest(type = "search")
	public Map<String,Object> showItems(DaRoom model){
		if(model.getId() ==  null) return null;
		model = genericService.view(model);
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		triggerCreateCharge(sdf, new Date(), model);
		genericService.refresh(model);
		
		Map<String,Object> resultMap = new HashMap<String,Object>();
		List<DaChargeItem> result = model.getChargeItems();
		resultMap.put("items", result);
		//拿到最近一次的帐单
		DaChargeBill bill = model.getChargeBills().get(0)==null?new DaChargeBill():model.getChargeBills().get(0); 
		resultMap.put("balance", bill.getBalance());
		
		return  resultMap;
	}
	
	/**
	 * 费用收取，实际上是修改item的状态为已收取.
	 * @param model
	 * @return
	 */
	@Rest(type = "update")
	public boolean updateItems(List<DaChargeItem> model, BigDecimal amountRecv,BigDecimal amountActual,List<DaChargeItem> otherFz,List<DaChargeItem> otherFee,Integer roomId,String remark){
		
		DaRoom room = null;
		boolean noRoom = true;
		List<DaChargeItem> items = new ArrayList<DaChargeItem>();
		for (DaChargeItem daChargeItem : model) {
			BigDecimal trureFee = daChargeItem.getPriceActual();//先把实收费用存起来
			
			daChargeItem.setPriceActual(null);
			daChargeItem = genericService.load(daChargeItem);
			
			daChargeItem.setStatus(DaChargeItem.STATUS_PAID);
			//实收金额先默认 
			daChargeItem.setPriceActual(trureFee);
			
			//取出item对应的room
			if(daChargeItem.getRoom()!=null && noRoom){
				room = daChargeItem.getRoom();
				noRoom = false;
			}
			items.add(daChargeItem);
		}
		
		//保证room的存在
		if( room == null)
		{
			room = new DaRoom();
			room.setId(roomId);
			room = genericService.load(room);
			if(room==null){
				return false;
			}
		}
		
		
		BigDecimal countOtherFz = new BigDecimal(0);
		//加入其它房租费用。
		if(otherFz.size()>0){
			for (DaChargeItem other : otherFz) {
				other.setStatus(DaChargeItem.STATUS_PAID);
				other.setName("房租");
				other.setChargeType(0);
				other.setPriceRecv(other.getPriceActual());
				countOtherFz =countOtherFz.add(other.getPriceActual());
				other.setRoom(room);
				items.add(other);
			}
		}
		
		BigDecimal countOtherF = new BigDecimal(0);
		//加入其它费用
		if(otherFee.size() > 0){
			for (DaChargeItem otherF : otherFee) {
				otherF.setStatus(DaChargeItem.STATUS_PAID);
				//表示固定杂费
				otherF.setChargeType(1);
				otherF.setPriceRecv(otherF.getPriceActual());
				countOtherF = countOtherF.add(otherF.getPriceActual());
				otherF.setDateBeginRecv(new Date());
				otherF.setDateEndRecv(new Date());
				otherF.setRoom(room);
				items.add(otherF);
			}
		}
		
		
		
		try{
			DaChargeBill bill = new DaChargeBill();
			bill.setRoom(room);
			bill.setChargeItems(items);
			bill.setAmountActual(amountActual);
		//	amountRecv = amountRecv.add(countOtherF).add(countOtherFz);
			bill.setAmountRecv(amountRecv);
			bill.setDateActual(new Date());
			bill.setRemark(remark);
			//余额，有可能是负的 表示欠多少。TODO 其它杂费也应该加入到里面
			BigDecimal balance = amountActual.subtract(amountRecv);
			bill.setBalance(balance);
			bill.setAgreement(room.getAgreement());
			genericService.add(bill);
			daFinanceStatementService.addInternal(room, amountActual, 1, new Date(), 0, remark);
		}catch(Exception e){
			logger.error("收取费用项，生成帐单时出错！！");
			return false;
		}
		
		return true;
	}
	
	
	
	/**
	 * 计算费用项的结束日期
	 * @param payNum
	 * @param beginDate
	 *  @param tagNum 1表示加payNum年  2表示加 payNum月 5表示加payNum天
	 * @return
	 */
	public Date getEndDate(Integer payNum,Date beginDate,Integer tagNum){
		Calendar c = Calendar.getInstance();
		c.setTime(beginDate);
		c.add(tagNum, payNum);
		return c.getTime();
	}
	
	
	/**
	 * 两个日期相减得到天数
	 * @param payNum
	 * @param beginDate
	 * @param tagNum
	 * @return
	 * @throws ParseException 
	 */
	 public static int daysBetween(Date before,Date curr) {
	        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");  
	        try {
				before=sdf.parse(sdf.format(before));
				curr=sdf.parse(sdf.format(curr));  
			} catch (ParseException e) {
				e.printStackTrace();
			} 
	        Calendar cal = Calendar.getInstance(); 
	        
	        cal.setTime(before);  
	        long beforeTime = cal.getTimeInMillis();  
	        
	        cal.setTime(curr);    
	        long currTime = cal.getTimeInMillis(); 
	        
	        long between_days=(currTime-beforeTime)/(1000*3600*24);  
	            
	        return Integer.parseInt(String.valueOf(between_days));
	        
	        
	  }
	 
	  
	 /**
	  * 判断一个日期是否在别两个日期之间 区期形式:( )
	  * @param checkDate
	  * @param startDate
	  * @param endDate
	  * @return
	 * @throws ParseException 
	  */
	 public static boolean betweenDate(Date checkDate,Date startDate,Date endDate) {
		boolean ret = false;
		try {
			if (compareDate(checkDate, startDate) > 0 && compareDate(checkDate, endDate) < 0) {
				ret = true;
			} else {
				ret = false;
			}
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return ret;
	 }
	 
	 
	/**
	 * 日期比较
	 * @param date1
	 * @param date2
	 * @return 1说明 date1比date2更早  -1 表示date1比date更晚 0表示两个日期相同
	 * @throws ParseException 
	 */
	private static int compareDate(Date date1,Date date2) throws ParseException{
		DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
		//纠正日期格式
		String date1Str = df.format(date1);
		String date2Str = df.format(date2);
		date1 = df.parse(date1Str);
		date2 = df.parse(date2Str);
		
		long date1L = date1.getTime();
		long date2L = date2.getTime();
		System.out.println(date1L-date2L);
		
		if(date1L<date2L){
			return -1;
		}else if(date1L>date2L){
			return 1;
		}else{
			return 0;
		}
		
	}
	
	public DaChargeBillRecord generateChargeBillRecord(DaRoom model) {
		if (model.getAgreement() == null || !Room.RENT_STATE_ALREADY.equals(model.getRentState())) {
			return null;
		}
		
		DaChargeBill example = new DaChargeBill();
		example.setAgreement(model.getAgreement());
		Condition condition = new Condition();
		condition.setSort("id");
		condition.setDir("desc");
		DaChargeBill dbChargeBill = genericService.searchByModel(example, condition).getData(0);
		DaChargeItem dblatestChargeItem = null;
		if (dbChargeBill != null) {
			DaChargeItem chargeItemExample = new DaChargeItem();
			chargeItemExample.setRoom(model);
			chargeItemExample.setStatus(DaChargeItem.STATUS_PAID);
			chargeItemExample.setChargeType(DaChargeItem.CHARGE_TYPE_RENTAL);
			dblatestChargeItem = genericService.searchByModel(chargeItemExample, condition).getData(0);
		}
		
		List<DaChargeItem> chargeItems = new ArrayList<DaChargeItem>();
		DaChargeBillRecord chargeBillRecord = new DaChargeBillRecord();
		chargeBillRecord.setAgreement(model.getAgreement());
		chargeBillRecord.setRoom(model);
		chargeBillRecord.setCreateTime(new Date());
		chargeBillRecord.setChargeItems(chargeItems);
		BigDecimal amountRecv = BigDecimal.ZERO;
		
		DaChargeItem chargeItem = new DaChargeItem();
		chargeItem.setName("房租");
		if (dbChargeBill == null) {
			chargeItem.setDateBeginRecv(model.getAgreement().getRentBeginDate());
			chargeItem.setDateEndRecv(DateTimeUtil.getFeeEndDate(chargeItem.getDateBeginRecv(), model.getAgreement().getPayNum()));
			chargeItem.setPriceRecv(model.getRentPay().multiply(BigDecimal.valueOf(model.getAgreement().getPayNum())));
		} else {
			chargeItem.setDateBeginRecv(DateTimeUtil.getOneDayAfter(dblatestChargeItem.getDateEndRecv()));
			chargeItem.setDateEndRecv(DateTimeUtil.getFeeEndDate(chargeItem.getDateBeginRecv(), model.getAgreement().getRentCycle() + 1));
			chargeItem.setPriceRecv(model.getRentPay().multiply(BigDecimal.valueOf(model.getAgreement().getRentCycle() + 1)));
			if (dbChargeBill.getBalance() != null) {
				amountRecv = amountRecv.subtract(dbChargeBill.getBalance());
			}
		}
		chargeBillRecord.setDateBeginRecv(chargeItem.getDateBeginRecv());
		chargeBillRecord.setDateEndRecv(chargeItem.getDateEndRecv());
		amountRecv = amountRecv.add(chargeItem.getPriceRecv());
		chargeItem.setRoom(model);
		chargeItem.setFeeRuleCfg(null);
		
		chargeItem.setStatus(DaChargeItem.STATUS_CONFIRMED);
		chargeItem.setChargeType(DaChargeItem.CHARGE_TYPE_RENTAL);
		chargeItem.setCreateChargeTime(new Date());
		chargeItems.add(chargeItem);
		
		if (dbChargeBill == null) {
			//新出租的房间，要产生押金
			chargeItem = new DaChargeItem();
			chargeItem.setName("押金");
			chargeItem.setDateBeginRecv(model.getAgreement().getRentBeginDate());
			chargeItem.setDateEndRecv(model.getAgreement().getRentEndDate());
			chargeItem.setRoom(model);
			chargeItem.setFeeRuleCfg(null);
			if (model.getDeposit() != null) {
				chargeItem.setPriceRecv(model.getDeposit());
			} else {
				chargeItem.setPriceRecv(model.getAgreement().getDeposit());
			}
			chargeItem.setPriceRecv(chargeItem.getPriceRecv().multiply(BigDecimal.valueOf(model.getAgreement().getDepositNum())));
			chargeItem.setStatus(DaChargeItem.STATUS_CONFIRMED);
			chargeItem.setChargeType(DaChargeItem.CHARGE_TYPE_DEPOSIT);
			chargeItem.setCreateChargeTime(new Date());
			amountRecv = amountRecv.add(chargeItem.getPriceRecv());
			chargeItems.add(chargeItem);
		}
		
		List<DaFeeRule> feeRules = null;
		if (DaSuite.RENT_TYPE_SUB.equals(model.getSuite().getRentType())) {
			feeRules = model.getFeeRules();
		} else {
			feeRules = model.getSuite().getFeeRules();
		}
		for (DaFeeRule feeRule : feeRules) {
			FeeRuleCfgCalc feeRuleCfgCalc = feeRule.getFeeRuleCfg().getFeeRuleCfgCalc();
			FeeRuleCfgDesc feeRuleCfgDesc = feeRule.getFeeRuleCfg().getFeeRuleCfgDesc();
			if (feeRuleCfgDesc.getType() == FeeRuleType.fixed) {
				chargeItem = new DaChargeItem();
				chargeItem.setName(feeRuleCfgDesc.getName());
				if (dbChargeBill == null) {
					chargeItem.setDateBeginRecv(model.getAgreement().getRentBeginDate());
					chargeItem.setDateEndRecv(DateTimeUtil.getFeeEndDate(chargeItem.getDateBeginRecv(), model.getAgreement().getPayNum()));
					chargeItem.setPriceRecv(feeRuleCfgCalc.getPrice().multiply(BigDecimal.valueOf(model.getAgreement().getPayNum())));
				} else {
					chargeItem.setDateBeginRecv(DateTimeUtil.getOneDayAfter(dblatestChargeItem.getDateEndRecv()));
					chargeItem.setDateEndRecv(DateTimeUtil.getFeeEndDate(chargeItem.getDateBeginRecv(), model.getAgreement().getRentCycle() + 1));
					chargeItem.setPriceRecv(feeRuleCfgCalc.getPrice().multiply(BigDecimal.valueOf(model.getAgreement().getRentCycle() + 1)));
				}
				
				chargeItem.setRoom(model);
				chargeItem.setFeeRuleCfg(feeRule.getFeeRuleCfg());
				if (feeRuleCfgDesc.getCalcMode() == FeeRuleCalcMode.areaFactor) {
					chargeItem.setPriceRecv(model.getArea().multiply(chargeItem.getPriceRecv()));
				}
				chargeItem.setStatus(DaChargeItem.STATUS_CONFIRMED);
				chargeItem.setChargeType(DaChargeItem.CHARGE_TYPE_FIXED);
				chargeItem.setCreateChargeTime(new Date());
				amountRecv = amountRecv.add(chargeItem.getPriceRecv());
				chargeItems.add(chargeItem);
			} else if (feeRuleCfgDesc.getType() == FeeRuleType.meter) {
				chargeItem = new DaChargeItem();
				chargeItem.setName(feeRuleCfgDesc.getName());
				if (dbChargeBill == null) {
					chargeItem.setDateBeginRecv(model.getAgreement().getRentBeginDate());
					chargeItem.setDateEndRecv(DateTimeUtil.getFeeEndDate(chargeItem.getDateBeginRecv(), model.getAgreement().getPayNum()));
				} else {
					chargeItem.setDateBeginRecv(DateTimeUtil.getOneDayAfter(dblatestChargeItem.getDateEndRecv()));
					chargeItem.setDateEndRecv(DateTimeUtil.getFeeEndDate(chargeItem.getDateBeginRecv(), model.getAgreement().getRentCycle() + 1));
				}
				chargeItem.setPriceRecv(BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP));
				chargeItem.setRoom(model);
				chargeItem.setFeeRuleCfg(feeRule.getFeeRuleCfg());
				chargeItem.setFeeRule(feeRule);
				chargeItem.setStatus(DaChargeItem.STATUS_CONFIRMED);
				chargeItem.setChargeType(DaChargeItem.CHARGE_TYPE_METER);
				chargeItem.setCreateChargeTime(new Date());
				DaMeter emptyMeter = feeRule.getMeter(0);
				if (emptyMeter == null) {
					emptyMeter = genericService.load(DaMeter.class, 0);
				}
				chargeItem.setMeter1(emptyMeter);
				chargeItem.setMeter2(emptyMeter);
				chargeItems.add(chargeItem);
			}
			
		}
		//chargeBillRecord.setAmountActual(amountRecv);
		chargeBillRecord.setAmountRecv(amountRecv);
		chargeBillRecord.setBalance(BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP));
		chargeBillRecord.setLandlordUser(model.getLandlordUser());
		chargeBillRecord.setStatus(DaChargeBillRecord.STATUS_RENT_TODO);
		return genericService.add(chargeBillRecord);
	}
	
	@Transactional
	public DaChargeBillRecord getOrGenerateChargeBillRecord(DaRoom model) {
		DaRoom dbRoom = genericService.load(model);
		if (DaRoom.RENT_STATE_RENT != dbRoom.getRentState() || dbRoom.getAgreement() == null) {
			return null;
		}
		
		DaChargeBillRecord dbLastestChargeBillRecords = null;
		List<DaChargeBillRecord> dbChargeBillRecords = dbRoom.getAgreement().getChargeBillRecords();
		if (dbChargeBillRecords == null || dbChargeBillRecords.size() == 0 || !DaChargeBillRecord.STATUS_RENT_TODO.equals(dbRoom.getAgreement().getChargeBillRecords().get(0).getStatus())) {
			dbLastestChargeBillRecords = generateChargeBillRecord(dbRoom);
		} else {
			dbLastestChargeBillRecords = dbRoom.getAgreement().getChargeBillRecords().get(0);
		}
		return dbLastestChargeBillRecords;
	}
	
	public void generateSharedFixedChargeItems(DaRoom model) {
		if (model.getAgreement() == null || !Room.RENT_STATE_ALREADY.equals(model.getRentState())) {
			return ;
		}
		List<DaFeeRule> feeRules = null;
		if (DaSuite.RENT_TYPE_SUB.equals(model.getSuite().getRentType())) {
			feeRules = model.getSuite().getFeeRules();
		}
		if (feeRules == null) {
			return ;
		}
		
		for (DaFeeRule feeRule : feeRules) {
			if (feeRule.getFeeRuleCfg().getFeeRuleCfgDesc().getType() != FeeRuleType.fixed) {
				continue;
			}
			List<DaRoom> rentRooms = feeRule.getSuite().getRentRooms();
			boolean needGenerate = true;
			for (DaRoom rentRoom : rentRooms) {
				String hql = "select count(a) from " + DaChargeItem.class.getName() + " a where a.room.id = " + rentRoom.getId() +" and a.status != " + DaChargeItem.STATUS_PAID + " and a.feeRuleCfg.id = " + feeRule.getFeeRuleCfg().getId();
				QLInfo qlInfo = new QLInfo(hql, false);
				int count = genericService.getCount(qlInfo, false);
				if (count != 0) {
					needGenerate = false;
					break;
				}
			}
			if (!needGenerate) {
				return;
			}
			List<DaChargeBillRecord> chargeBillRecords = new ArrayList<DaChargeBillRecord>(rentRooms.size());
			int sumDays = 0;
			List<Integer> intervalDays = new ArrayList<Integer>();
			for (DaRoom rentRoom : rentRooms) {
				DaChargeBill example = new DaChargeBill();
				example.setAgreement(rentRoom.getAgreement());
				Condition condition = new Condition();
				condition.setSort("id");
				condition.setDir("desc");
				DaChargeBill dbChargeBill = genericService.searchByModel(example, condition).getData(0);
				if (dbChargeBill != null) {
					int intervalDay = DateTimeUtil.getIntervalDays(dbChargeBill.getChargeItems().get(0).getDateBeginRecv(), dbChargeBill.getChargeItems().get(0).getDateEndRecv());
					intervalDays.add(intervalDay);
					sumDays += intervalDay;
					DaChargeBillRecord dbChargeBillRecord = getOrGenerateChargeBillRecord(rentRoom);
					chargeBillRecords.add(dbChargeBillRecord);
				}
			}
			
			for (int i = 0; i< chargeBillRecords.size(); i++) {
				DaChargeItem chargeItem = new DaChargeItem();
				chargeItem.setName(feeRule.getFeeRuleCfg().getFeeRuleCfgDesc().getName());
				chargeItem.setDateBeginRecv(chargeBillRecords.get(i).getDateBeginRecv());
				chargeItem.setDateEndRecv(chargeBillRecords.get(i).getDateEndRecv());
				chargeItem.setPriceRecv(feeRule.getFeeRuleCfg().getFeeRuleCfgCalc().getPrice().multiply(BigDecimal.valueOf(intervalDays.get(i)).divide(BigDecimal.valueOf(sumDays), 2, RoundingMode.HALF_UP)));
				chargeItem.setRoom(rentRooms.get(i));
				chargeItem.setFeeRuleCfg(feeRule.getFeeRuleCfg());
				if (feeRule.getFeeRuleCfg().getFeeRuleCfgDesc().getCalcMode() == FeeRuleCalcMode.areaFactor) {
					chargeItem.setPriceRecv(model.getArea().multiply(chargeItem.getPriceRecv()));
				}
				chargeItem.setStatus(DaChargeItem.STATUS_CONFIRMED);
				chargeItem.setChargeType(DaChargeItem.CHARGE_TYPE_FIXED);
				chargeItem.setChargeBillRecord(chargeBillRecords.get(i));
				chargeItem.setCreateChargeTime(new Date());
				genericService.add(chargeItem);
			}
		}
	}
	
	@Transactional
	public void repaireFixedChargeItem(DaSuite suite) {
		suite = em.find(DaSuite.class, suite.getId());
		em.refresh(suite);
		if (DaSuite.RENT_TYPE_ENTIRE.equals(suite.getRentType())) {	//整租
			DaChargeBillRecord dbChargeBillRecord = getOrGenerateChargeBillRecord(suite.getRooms().get(0));
			RentalOrder rentalOrder = rentalOrderService.searchRentalOrderByChargeBillRecord(dbChargeBillRecord);
			BigDecimal price = new BigDecimal(0);
			List<DaChargeItem> deletedChargeItems = new ArrayList<DaChargeItem>();
			if (dbChargeBillRecord != null && (rentalOrder == null || rentalOrder.getOrderState() == RentalOrder.ORDER_STATE_WAITING_PAYMENT || rentalOrder.getOrderState() == RentalOrder.ORDER_STATE_SUCCESS || rentalOrder.getOrderState() == RentalOrder.ORDER_STATE_CLOSED)) {
				for (DaChargeItem chargeItem : dbChargeBillRecord.getChargeItems()) {
					if (DaChargeItem.CHARGE_TYPE_FIXED.equals(chargeItem.getChargeType())) {
						if (rentalOrder == null || DaChargeItem.STATUS_NEED_CONFIRM.equals(chargeItem.getStatus())) {
							price = price.subtract(chargeItem.getPriceRecv());
							deletedChargeItems.add(chargeItem);	
						}
					}
				}
				dbChargeBillRecord.getChargeItems().removeAll(deletedChargeItems);
				if (suite.getFeeRules() != null) {
					for (DaFeeRule feeRule : suite.getFeeRules()) {
						if (feeRule.getFeeRuleCfg().getFeeRuleCfgDesc().getType() != FeeRuleType.fixed) {
							continue ;
						}
						boolean needGenerateChargeItem = true;
						for (DaChargeItem chargeItem : dbChargeBillRecord.getChargeItems()) {
							if (chargeItem.getFeeRuleCfg() != null && chargeItem.getFeeRuleCfg().getId().equals(feeRule.getFeeRuleCfg().getId())) {
								needGenerateChargeItem =false;
								break ;
							}
						}
						if (!needGenerateChargeItem) {
							continue ;
						}
						int monthDist = dbChargeBillRecord.getRoom().getAgreement().getRentCycle() + 1;
						List<DaChargeBill> chargeBills = dbChargeBillRecord.getRoom().getAgreement().getChargeBills();
						if (chargeBills == null || chargeBills.size() == 0) {
							monthDist = dbChargeBillRecord.getRoom().getAgreement().getPayNum();
						}
						DaChargeItem chargeItem = new DaChargeItem();
						chargeItem.setName(feeRule.getFeeRuleCfg().getFeeRuleCfgDesc().getName());
						chargeItem.setDateBeginRecv(dbChargeBillRecord.getDateBeginRecv());
						chargeItem.setDateEndRecv(dbChargeBillRecord.getDateEndRecv());
						chargeItem.setPriceRecv(feeRule.getFeeRuleCfg().getFeeRuleCfgCalc().getPrice().multiply(BigDecimal.valueOf(monthDist)));
						chargeItem.setRoom(suite.getRooms().get(0));
						chargeItem.setFeeRuleCfg(feeRule.getFeeRuleCfg());
						if (feeRule.getFeeRuleCfg().getFeeRuleCfgDesc().getCalcMode() == FeeRuleCalcMode.areaFactor) {
							chargeItem.setPriceRecv(suite.getRooms().get(0).getArea().multiply(chargeItem.getPriceRecv()));
						}
						if (rentalOrder == null) {
							chargeItem.setStatus(DaChargeItem.STATUS_CONFIRMED);
						} else {
							chargeItem.setStatus(DaChargeItem.STATUS_NEED_CONFIRM);
						}
						chargeItem.setChargeType(DaChargeItem.CHARGE_TYPE_FIXED);
						chargeItem.setCreateChargeTime(new Date());
						price = price.add(chargeItem.getPriceRecv());
						dbChargeBillRecord.getChargeItems().add(chargeItem);
					}
					dbChargeBillRecord.setAmountRecv(dbChargeBillRecord.getAmountRecv().add(price));
				}
			}
		} else {	//分租
			for (DaRoom room : suite.getRooms()) {
				DaChargeBillRecord dbChargeBillRecord = getOrGenerateChargeBillRecord(room);
				RentalOrder rentalOrder = rentalOrderService.searchRentalOrderByChargeBillRecord(dbChargeBillRecord);
				BigDecimal price = new BigDecimal(0);
				List<DaChargeItem> deletedChargeItems = new ArrayList<DaChargeItem>();
				if (dbChargeBillRecord != null && (rentalOrder == null || rentalOrder.getOrderState() == RentalOrder.ORDER_STATE_WAITING_PAYMENT)) {
					//删除该room下所有非公摊的固定费用
					for (DaChargeItem chargeItem : dbChargeBillRecord.getChargeItems()) {
						if (DaChargeItem.CHARGE_TYPE_FIXED.equals(chargeItem.getChargeType())) {
							if (suite.getFeeRules() != null) {
								for (DaFeeRule feeRule : suite.getFeeRules()) {
									if (feeRule.getFeeRuleCfg().getId().equals(chargeItem.getFeeRuleCfg().getId())) {
										continue;
									}
								}
							}
							if (rentalOrder == null || DaChargeItem.STATUS_NEED_CONFIRM.equals(chargeItem.getStatus())) {
								deletedChargeItems.add(chargeItem);
								price = price.subtract(chargeItem.getPriceRecv());
							}
								
						}
					}
					dbChargeBillRecord.getChargeItems().removeAll(deletedChargeItems);
					//根据新的room下的固定费用生成chargeItem
					if (room.getFeeRules() != null) {
						for (DaFeeRule feeRule : room.getFeeRules()) {
							if (feeRule.getFeeRuleCfg().getFeeRuleCfgDesc().getType() != FeeRuleType.fixed) {
								continue;
							}
							boolean needGenerateChargeItem = true;
							for (DaChargeItem chargeItem : dbChargeBillRecord.getChargeItems()) {
								if (chargeItem.getFeeRuleCfg() != null && chargeItem.getFeeRuleCfg().getId().equals(feeRule.getFeeRuleCfg().getId())) {
									needGenerateChargeItem =false;
									break ;
								}
							}
							if (!needGenerateChargeItem) {
								continue ;
							}
							int monthDist = dbChargeBillRecord.getRoom().getAgreement().getRentCycle() + 1;
							List<DaChargeBill> chargeBills = dbChargeBillRecord.getRoom().getAgreement().getChargeBills();
							if (chargeBills == null || chargeBills.size() == 0) {
								monthDist = dbChargeBillRecord.getRoom().getAgreement().getPayNum();
							}
							DaChargeItem chargeItem = new DaChargeItem();
							chargeItem.setName(feeRule.getFeeRuleCfg().getFeeRuleCfgDesc().getName());
							chargeItem.setDateBeginRecv(dbChargeBillRecord.getDateBeginRecv());
							chargeItem.setDateEndRecv(dbChargeBillRecord.getDateEndRecv());
							chargeItem.setPriceRecv(feeRule.getFeeRuleCfg().getFeeRuleCfgCalc().getPrice().multiply(BigDecimal.valueOf(monthDist)));
							chargeItem.setRoom(suite.getRooms().get(0));
							chargeItem.setFeeRuleCfg(feeRule.getFeeRuleCfg());
							if (feeRule.getFeeRuleCfg().getFeeRuleCfgDesc().getCalcMode() == FeeRuleCalcMode.areaFactor) {
								chargeItem.setPriceRecv(suite.getRooms().get(0).getArea().multiply(chargeItem.getPriceRecv()));
							}
							chargeItem.setStatus(DaChargeItem.STATUS_CONFIRMED);
							chargeItem.setChargeType(DaChargeItem.CHARGE_TYPE_FIXED);
							chargeItem.setCreateChargeTime(new Date());
							price = price.add(chargeItem.getPriceRecv());
							dbChargeBillRecord.getChargeItems().add(chargeItem);
						}
						dbChargeBillRecord.setAmountRecv(dbChargeBillRecord.getAmountRecv().add(price));
					}
				}
			}
		}
	}

}
